package KIMS;


public class KIMS {

	/**
	 * 对原始数据样本进行标准化处理
	 * @param sample 原始数据样本
	 * @return 处理成功返回true，否则返回false
	 */
	private boolean handleSample(double[][] sample,double[][] standard){
		int column=sample[0].length;//列数
		int row=sample.length;//行数
		//		double[][] standard=new double[row][column];//处理之后的标准化矩阵
		double[] sd=new double[column];//每列数据的标准差。sd代表标准差standard deviation
		double[] average=new double[column];//计算每列的平均值


		//首先根据公式计算每列平均值average
		for(int i=0;i<column;i++){  //按列遍历
			for(int j=0;j<row;j++)//对于每一列，遍历这一列的所有行
				average[i]+=sample[j][i];
			average[i]/=row;
		}

		//计算每列的方差sd
		for(int i=0;i<column;i++){
			for(int j=0;j<row;j++)
				sd[i]+=(sample[j][i]-average[i])*(sample[j][i]-average[i]);
			sd[i]=Math.sqrt(sd[i]/row);
		}

		//计算标准化矩阵standard
		for(int i=0;i<column;i++){
			for(int j=0;j<row;j++)
				standard[j][i]=(sample[j][i]-average[i])/sd[i];
		}

		return true;
	}

	/**
	 * 对标准化矩阵进行处理,生成相关系数矩阵
	 * 需要调用computeNumerator和computeDenominator
	 * @param standard 标准化矩阵
	 * @param rc 初始化的相关系数矩阵
	 * @return 处理相关系数矩阵成功返回
	 */
	private boolean handleStandard(double[][] standard,double[][] rc){
		int column=standard[0].length;//列数
		int row=standard.length;//行数
		double[] sarow=new double[row];//标准化矩阵的行平均值
		double[] sacolumn=new double[column];//标准化矩阵的列平均值

		//计算标准化矩阵的行平均值sarow
		for(int i=0;i<row;i++){
			for(int j=0;j<column;j++)
				sarow[i]+=standard[i][j];
			sarow[i]/=column;
		}

		//计算标准化矩阵的列平均值sacolumn
		for(int i=0;i<column;i++){
			for(int j=0;j<row;j++)
				sacolumn[i]+=standard[j][i];
			sarow[i]/=row;
		}

		/*相关系数矩阵是column*column阶的方阵，所以下面的遍历都是在column范围内*/
		//构造相关系数矩阵rc
		for(int i=0;i<column;i++)
			for(int j=0;j<column;j++)
				rc[i][j]=computeNumerator(standard, sarow, sacolumn, i, j, row)/(computeDenominator(standard, sarow, i, row)*computeDenominator(standard, sacolumn, j, row));
		
		return true;
	}


	/**
	 * 计算相关系数矩阵公式中的分子
	 * 被handleSample调用
	 * @param standard 标准化矩阵
	 * @param sarow 标准化矩阵行平均值
	 * @param sacolumn 标准化矩阵列平均值
	 * @param i 相关系数矩阵中元素的行下标
	 * @param j 相关系数矩阵中元素的列下标
	 * @param row 循环累加次数，也就是标准化矩阵的行数
	 * @return 返回double类型计算结果
	 */
	private double computeNumerator(double[][] standard,double[] sarow,double[] sacolumn,int i,int j,int row){
		double result=0;
		for(int k=0;k<row;k++){
			result+=(standard[k][i]-sarow[i])*(standard[k][j]-sacolumn[j]);
		}
		return result;
	}

	/**
	 * 计算相关系数矩阵公式中的分母
	 * 被handleSample调用
	 * @param standard 标准化矩阵
	 * @param sa 标准化矩阵行或列平均值，实际含义根据实际传入的参数是行相关还是列相关而定
	 * @param k 相关系数矩阵中元素的行或列下标，实际含义根据实际传入的参数是行相关还是列相关而定
	 * @param row 循环累加次数，也就是标准化矩阵的行数
	 * @return 返回double类型计算结果
	 */
	private double computeDenominator(double[][] standard,double[] sa,int k,int row){
		double result=0;
		for(int i=0;i<row;i++)
			result+=(standard[i][k]-sa[k])*(standard[i][k]-sa[k]);
		return Math.sqrt(result);
	}

	/**
	 * 选取需要删减的元素所对应的矩阵下标
	 * @param matrix 实对称矩阵,对角线元素为特征值
	 * @param ortho 特征向量矩阵
	 * @return 相关系数矩阵的列标，即需要删减的指标的下标
	 */
	private int delIndexNum(Index index){

		double[][] matrix=index.getRc();
		double[][] ortho=index.getOrtho();
		double temp=matrix[0][0];//临时替换变量
		double temp1=ortho[0][0];//临时替换变量
		int column=0;//最小特征值的列标
		int row=0;//特征向量最大分量的行标

		//matrix对角线中选取最小值（即最小特征值）
		for(int i=0;i<matrix.length;i++)
			if(matrix[i][i]<temp){
				temp=matrix[i][i];
				column=i;
			}
		index.setDelcontribute(index.getDelcontribute()+temp);
		//求最小特征值对应的特征向量的最大分量的列标
		for(int i=0;i<ortho.length;i++)
			if(ortho[i][column]>temp1){
				temp1=ortho[i][column];
				row=i;
			}
		return row;
	}
	
	/**
	 * 筛选指标
	 * @param index 指标对象
	 * @return 筛选成功返回true，否则返回false
	 */
	public boolean filterIndex(Index index){
		double[][] sample=index.getSample();
		double[][] standard=index.getStandard();
		double[][] rc=index.getRc();
		double charac=index.getCharacteristic();
		double charactertemp=0;//保存特征值之和的变量，初值为0
		int delnum;//需要删减的指标标号
		handleSample(sample,standard);
		handleStandard(standard,rc);
		index.copyOrtho(rc);//保存相关系数矩阵的一个副本
		Jacobi.computeJacobi(rc, index.getUnitmatrix(), index.getOrtho(), index.getEps());
		if(charac==0){
			for(int i=0;i<rc.length;i++)
				charactertemp+=rc[i][i];
			index.setCharacteristic(charactertemp);
		}
		delnum=delIndexNum(index);
		index.delIndex(delnum);
		return true;
	}
}
